﻿using System;
using System.Collections.Generic;
using System.Net;

using Netbits.Common.Extensions;
using Netbits.Common.Conditions;

namespace Netbits.Common.Network
{
	/// <summary>
	/// Represents one or more IP-Endpoints.
	/// </summary>
	public class BindEndPoint
	{
		#region Private Variables

		readonly List<IPEndPoint> _EndPoints;

		#endregion

		#region Constructors

		BindEndPoint()
		{
			_EndPoints = new List<IPEndPoint>();
		}

		/// <summary>
		/// Create new instance of BindEndPoint with specified IP and Port address.
		/// </summary>
		/// <param name="Ip_">The IP Address</param>
		/// <param name="Port_">The Port Address</param>
		public BindEndPoint( IPAddress Ip_, int Port_ ) : this()
		{
			Condition.Requires( Ip_, "Ip_" ).IsNotNull();
			Condition.Requires( Port_, "Port_" ).IsNotNull().IsInRange( 0, 65535 );

			_EndPoints.Add( new IPEndPoint( Ip_, Port_ ) );
		}

		/// <summary>
		/// Create new instance of BindEndPoint with specified HostName and Port address.
		/// Use all specified IP-addresses for specified HostName.
		/// </summary>
		/// <param name="HostName_">The Host-Name</param>
		/// <param name="Port_">The Port Address</param>
		public BindEndPoint( string HostName_, int Port_ ) : this()
		{
			Condition.Requires( HostName_, "HostName_" ).IsNotNull().IsNotEmpty();
			Condition.Requires( Port_, "Port_" ).IsNotNull().IsInRange( 0, 65535 );

			IPAddress[] addresses = Dns.GetHostAddresses( HostName_ );
			foreach( IPAddress ip in addresses )
			{
				_EndPoints.Add( new IPEndPoint( ip, Port_ ) );
			}
		}

		/// <summary>
		/// Create new instance of BindEndPoint with specified Bind-EndPoint-String.
		/// String syntax:
		///		192.168.0.1:2020;10.10.10.1:3333;....
		/// </summary>
		/// <param name="BindEndPointString_"></param>
		public BindEndPoint( string BindEndPointString_ ) : this()
		{
			Condition.Requires( BindEndPointString_, "BindEndPointString_").IsNotNull().IsNotEmpty();

			string[] splitEndPoints = BindEndPointString_.Split( new char[] { ';' } );
			if( splitEndPoints == null || splitEndPoints.Length == 0 )
				throw new Exception( "" );

			foreach( string endpoint in splitEndPoints )
			{
				string[] splitEndPoint = endpoint.Split( new char[] { ':' } );
				if( splitEndPoint == null || splitEndPoint.Length == 0 )
					continue;

				int port = splitEndPoint[1].ConvertTo<int>( -1 );
				if( port == -1 )
					continue;

				if( port > 65535 )
					continue;

				IPAddress[] addresses = Dns.GetHostAddresses( splitEndPoint[0] );
				foreach( IPAddress ip in addresses )
				{
					_EndPoints.Add( new IPEndPoint( ip, port ) );
				}
			}
		}

		#endregion

		#region Public Properties

		/// <summary>
		/// Gets the count of IPEndPoints.
		/// </summary>
		public int Count
		{
			get
			{
				return _EndPoints.Count;
			}
		}

		#endregion

		#region Public Functions

		/// <summary>
		/// Get the IPEndPoint for the specified index position
		/// </summary>
		/// <param name="Index_">The index position</param>
		/// <returns>The IPEndPoint on index position; otherwise null</returns>
		public IPEndPoint Get( int Index_ )
		{
			if( Index_ > _EndPoints.Count - 1 )
				return null;

			return _EndPoints[Index_];
		}

		#endregion
	}
}
